package org.zero.onlinesubject.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.util.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.zero.onlinesubject.common.constant.RedisConstant;
import org.zero.onlinesubject.common.param.LoginParam;
import org.zero.onlinesubject.common.param.RegisterParam;
import org.zero.onlinesubject.common.vo.Result;
import org.zero.onlinesubject.common.vo.UserVo;
import org.zero.onlinesubject.entity.Role;
import org.zero.onlinesubject.entity.User;
import org.zero.onlinesubject.mapper.RoleMapper;
import org.zero.onlinesubject.service.EmailService;
import org.zero.onlinesubject.service.UserService;
import org.zero.onlinesubject.mapper.UserMapper;
import org.springframework.stereotype.Service;
import org.zero.onlinesubject.utils.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Resource
    private Md5Util md5Util;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private EmailService emailService;

    @Value("${file.external_path}")
    private String externalPath;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result<String> doLogin(LoginParam param, boolean fromRegister) {
        String pass = md5Util.inputPassToDBPass(param.getPassword());
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("Username",param.getUsername())
                .eq("Password",pass)
                .last(" limit 1");
        User user = userMapper.selectOne(wrapper);

        if(user==null) return Result.error(500,"用户名或密码错误");
        String userId = user.getUserid();
        String token = jwtUtil.createToken(userId);

        stringRedisTemplate.opsForValue().set(RedisConstant.TOKEN_PREFIX+userId,JSON.toJSONString(user),2,TimeUnit.HOURS);
        return Result.ok(token);
    }

    @Override
    public Result<User> doRegister(RegisterParam param) {
        if(!ValidatorUtil.isName(param.getUsername())){
            return Result.error(500,"用户名格式错误");
        }
        if(param.getPhone() !=null && !ValidatorUtil.isPhone(param.getPhone())){
            return Result.error(500,"手机号格式错误");
        }
        if(param.getEmail() !=null && !ValidatorUtil.isEmail(param.getEmail())){
            return Result.error(500,"邮箱格式错误");
        }

        User user = new User();
        user.setUserid(param.getUserId());
        user.setUsername(param.getUsername());
        user.setPassword(md5Util.inputPassToDBPass(param.getPassword()));
        user.setPhone(param.getPhone());
        user.setRoleid(param.getRoleId());
        user.setAge(param.getAge());
        user.setGender(param.getGender());
        user.setAvatar(externalPath + param.getAvatar());
        user.setLearnCount(0);
        System.out.println("---------------------开始登录---------------------");

        boolean flag = save(user);
        if(!flag){
            return Result.error(500,"添加用户失败");
        }

        return Result.ok(user);
    }

    @Override
    public List<Role> getRoleList() {
        return roleMapper.selectList(null);
    }

    @Override
    public UserVo getUserVo(String userid) {
        String json = stringRedisTemplate.opsForValue().get(RedisConstant.USER_INFO_PREFIX + userid);
        UserVo userVo = null;
        if(!StringUtils.isNullOrEmpty(json)){
            userVo = JSON.parseObject(json, UserVo.class);
            return userVo;
        }

        userVo = userMapper.getUserVo(userid);
        DataDesensitizationUtil.desensitizeUserData(userVo);
        stringRedisTemplate.opsForValue().set(RedisConstant.USER_INFO_PREFIX+userid,JSON.toJSONString(userVo),2,TimeUnit.HOURS);
        return userVo;
    }

    @Override
    public List<UserVo> getUserList(String classId, Integer roleId, Integer current, Integer size) {
        return userMapper.getUserList(classId,roleId,current,size);
    }

    @Override
    public int getUserCount(String classId, Integer roleId) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("ClassID",classId)
            .eq("RoleID",roleId);
        Long count = userMapper.selectCount(wrapper);
        return count.intValue();
    }

    @Override
    public Boolean pwdChange(String newPass) {
        User user = UserContextHolder.get();

        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.eq("UserID",user.getUserid())
               .set("Password",md5Util.inputPassToDBPass(newPass))
               .last(" limit 1");
        return userMapper.update(wrapper) == 1;
    }

    @Override
    public Boolean sendCaptcha(String email) {
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(RedisConstant.EMAIL_PREFIX + email))) {
            return false;
        }
        String code = generateCode();
        stringRedisTemplate.opsForValue().set(RedisConstant.EMAIL_PREFIX + email,code,5, TimeUnit.MINUTES);
        emailService.sendHtmlMail(email,"云课堂验证码",code);
        return true;
    }

    @Override
    public Result<String> checkCode(String email, String code) {
        String json = stringRedisTemplate.opsForValue().get(RedisConstant.EMAIL_PREFIX + email);
        if(StringUtils.isNullOrEmpty(json)){
            return Result.error(500,"验证码错误");
        }
        if(!code.equals(json)){
            return Result.error(500,"验证码错误");
        }
        stringRedisTemplate.delete(RedisConstant.EMAIL_PREFIX + email);
        return Result.ok("验证成功");
    }

    @Override
    public Boolean verifyCaptcha(String code) {
        return MyCaptchaUtil.checkCode(code);
    }

    private String generateCode(){
        String avaliableChars = "0123456789";
        StringBuilder sb = new StringBuilder();
        Random random = new Random();

        int i = 0;
        while(i<6){
            i++;
            sb.append( avaliableChars.charAt(random.nextInt(10)));
        }
        return sb.toString();
    }
}




